/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AEQuaternion.h
// Author:		Gianluca Belardelli
// Date:		31/07/2013
// Purpose:		Dichiarazione della classe AEQuaternion
//
// Revision:
//				001 - 31/07/2013
//					+ Revisione iniziale
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AE_QUATERNION_H_
#define _AE_QUATERNION_H_
/*
#include <core/math/AEMath.h>
#include <core/math/vector/AEVector3.h>
#include <core/math/matrix/AEMatrix3.h>
#include <core/math/matrix/AEMatrix4.h>
*/
/// \brief A quaternion class that can be used to represent rotations.
class AEQuaternion
{
// Members
public:
	float fX, fY, fZ, fW;

// Methods
private:
	void operator&( void );

public:
	///////////////////////////////////////////////////////////////
	/// @name Costruttori
	/// @{
	///////////////////////////////////////////////////////////////

	/// \brief
	/// Costruttore di default. L'oggetto non viene inizializzato.
	AE_FORCEINLINE AEQuaternion( void ) { }
	
	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Funzioni statiche
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief Static function that returns an identity quaternion (ie. no rotation).
	AE_FORCEINLINE static const AEQuaternion IdentityQuaternion( void );
	
	/// \brief Normalizes the quaternion to unit length. Only a normalized quaternion represents a valid rotation.
	AE_FORCEINLINE void Normalize( void );
	
	/// \brief Checks whether the quaternion is normalized withing some epsilon range.
	AE_FORCEINLINE bool IsNormalized( float fEpsilon = AEMATH_GIGANTIC_EPSILON ) const;
	
	/// \brief Inverts the rotation that the quaternion represents.
	AE_FORCEINLINE void Invert( void );
	
	/// \brief Sets the quaternion to identity.
	AE_FORCEINLINE void SetIdentity( void );
	
	/// \brief Checks whether the quaternion is the identity quaternion.
	AE_FORCEINLINE bool IsIdentity( float fEpsilon = AEMATH_LARGE_EPSILON ) const;
	
	/// \brief Returns the length of the quaternion. Will always be 1 for quaternions that represent valid rotations.
	AE_FORCEINLINE float GetLength( void ) const;
	
	/// \brief Returns the squared length of the quaternion.
	AE_FORCEINLINE float GetLengthSquared( void ) const;
	
	/// \brief Creates the quaternion from a 3x3 matrix.
	AE_FORCEINLINE void SetFromMat3( const AEMatrix3 &matRotation );
	
	/// \brief Sets the quaternion from a rotation axis and and angle.
	///
	/// \param vAxis
	///   The rotation axis. Must be normalized.
	///
	/// \param fAngleDeg
	///   The amount of rotation around the axis, given in degree.
	///   The rotation will be counter-clockwise around the rotation axis.
	///
	// /// \sa getAxisAndAngle
	AE_FORCEINLINE void SetFromAxisAndAngle( const AEVector3 &vcAxis, float fAngleDeg );
	
	/// \brief Creates a quaternion from euler angles.
	AE_FORCEINLINE void SetFromEulerAngles( float fRollDeg, float fPitchDeg, float fYawDeg );
	
	/// \brief Returns euler angles which represent the same rotation as this quaternion.
	AE_FORCEINLINE void GetAsEulerAngles( float &fRollDeg, float &fPitchDeg, float &fYawDeg );
	
	/// \brief Returns a 3x3 matrix that represents the same rotation as this quaternion.
	AE_FORCEINLINE const AEMatrix3 GetAsMat3( void ) const;
	
	/// \brief Returns a 4x4 matrix that represents the same rotation as this quaternion.
	AE_FORCEINLINE const AEMatrix4 GetAsMat4( void ) const;
	
	/// \brief Returns an inverted quaternion, ie. one that rotates into the opposite direction.
	AE_FORCEINLINE const AEQuaternion operator- ( void ) const;
	
	/// \brief Returns the rotation axis and angle of this quaternion.
	///
	/// \param out_vRotationAxis
	///   The rotation axis is stored here. Will be normalized.
	///
	/// \param out_fAngles
	///   The rotation angle will be stored here. 
	///   The rotation is supposed to be counter-clockwise around the rotation axis.
	///
	/// \sa setFromAxisAndAngle
	AE_FORCEINLINE void GetAxisAndAngle( AEVector3 &vcRotationAxis, float &fAngle ) const;
	
	/// \brief
	///   Will check whether two quaternions are identical.
	///
	/// Since a quaternion is equal to itself with all components negated, that will also
	/// be taken into account. Thus (x,y,z,w) will be considered equal to (-x,-y,-z,-w).
	/// Generally this function creates two matrices from the two quaternions and compares those for equality.
	/// This function should only be used in unit-tests.
	///
	/// \param rhs      The right-hand side quaternion to check.
	AE_FORCEINLINE bool IsIdentical( const AEQuaternion &qtRhs ) const;
	
	/// \brief
	///   Will check whether two quaternions are equal within some epsilon range.
	///
	/// Since a quaternion is equal to itself with all components negated, that will also
	/// be taken into account. Thus (x,y,z,w) will be considered equal to (-x,-y,-z,-w).
	/// Generally this function creates two matrices from the two quaternions and compares those for equality.
	/// This function should only be used in unit-tests.
	///
	/// \param rhs      The right-hand side quaternion to check.
	/// \param fEpsilon The allowed epsilon range.
	AE_FORCEINLINE bool IsEqual( const AEQuaternion &qtRhs, float fEpsilon ) const;
	
	/// \brief Computes the 4-component dot-product between the two quaternions.
	AE_FORCEINLINE float Dot( const AEQuaternion &qtRhs ) const;
	
	/// \brief Sets this quaternion to the shortest rotation quaternion that would rotate the direction vector 'vFrom' to 'vTo'.
	///
	/// This function can be used to take two directions and create a quaternion that defines how to
	/// rotate the direction 'vFrom' such that it becomes 'vTo'.
	///
	/// \param vFrom
	///   Original direction vector. Must be normalized.
	///
	/// \param vTo
	///   Target direction vector. Must be normalized.
	void SetShortestRotation( const AEVector3 &vcFrom, const AEVector3 &vcTo );
	
	/// \brief Concatenates two rotations. This operation is not commutative.
	AE_FORCEINLINE const AEQuaternion Multiply( const AEQuaternion &qtRhs ) const;
	
	/// \brief Concatenates two rotations in the reverse order than 'multiply' does. This operation is not commutative.
	AE_FORCEINLINE const AEQuaternion MultiplyReverse( const AEQuaternion &qtRhs ) const;
	
	/// \brief Transforms (rotates) the given vector by this quaternion.
	AE_FORCEINLINE const AEVector3 Transform( const AEVector3 &qtRhs ) const;
	
	/// \brief Transforms (rotates) the given vector by the inverse of this quaternion. Ie. rotates it into the opposite direction.
	AE_FORCEINLINE const AEVector3 TransformReverse( const AEVector3 &qtRhs ) const;
	
	/// \brief Flips the sign of all four components.
	AE_FORCEINLINE void FlipSigns( void );
	
	/// \brief Sets the 4 components of this quaternion.
	AE_FORCEINLINE void SetValuesDirect( float _fX, float _fY, float _fZ, float _fW) { fX = _fX; fY = _fY; fZ = _fZ; fW = _fW; }
	
	/// \brief Returns the x component.
	AE_FORCEINLINE float GetX( void ) const { return fX; }
	
	/// \brief Returns the y component.
	AE_FORCEINLINE float GetY( void ) const { return fY; }
	
	/// \brief Returns the z component.
	AE_FORCEINLINE float GetZ( void ) const { return fZ; }
	
	/// \brief Returns the w component.
	AE_FORCEINLINE float GetW( void ) const { return fW; }
	
	/// \brief Checks whether the 4 components are all valid (ie. not NaN or infinity). Does NOT check whether the quaternion is normalized.
	AE_FORCEINLINE bool IsValid( void ) const;
	
	/// \brief Returns a float pointer to the internal data.
	AE_FORCEINLINE const float *GetDataPointer( void ) const { return &fX; }
	
	/// \brief Returns a float pointer to the internal data.
	AE_FORCEINLINE float *GetDataPointer( void ) { return &fX; }
	
	/// \brief Sets this quaternion to the spherical interpolation of 'qFrom' and 'qTo' by the factor 't'.
	void SetSlerp( const AEQuaternion &qtFrom, const AEQuaternion &qtTo, float fFactor );
};

/// \brief Rotates the vector rhs by the quaternion lhs.
AE_FORCEINLINE const AEVector3 operator* ( const AEQuaternion &qtLhs, const AEVector3 &vcRhs );

/// \brief Concatenates the rotations of lhs and rhs.
AE_FORCEINLINE const AEQuaternion operator* ( const AEQuaternion &qtLhs, const AEQuaternion &qtRhs );

/// \brief Compares the two quaternions for equality.
AE_FORCEINLINE bool operator== ( const AEQuaternion &qtLhs, const AEQuaternion &qtRhs );

/// \brief Compares the two quaternions for inequality.
AE_FORCEINLINE bool operator!= ( const AEQuaternion &qtLhs, const AEQuaternion &qtRhs );

#include <core/math/quaternion/AEQuaternion.inl>

#endif
// _AE_QUATERNION_H_